//=============================================================================
// System  : MatchKit
// File    : Match.cs
// Author  : Fabio Bussu  (matchkit@fabiobussu.it)
// Updated : 04/16/2013
// Note    : Copyright 2013, Fabio Bussu, All rights reserved
//
// This code is published under the Microsoft Public License (Ms-PL). A copy
// of the license should be distributed with the code.  It can also be found
// at the project website: http://matchkit.codeplex.com. This notice, the
// author's name, and all copyright notices must remain intact in all
// applications, documentation, and source files.
//
// Version     Date     Who  Comments
// ============================================================================
// 1.0.0.0  04/16/2013   FB  First draft
//=============================================================================
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace MatchKit
{
	/// <summary>
	/// Collects informations about a failed or found match.
	/// </summary>
	/// <threadsafety static="true" instance="false" />
	/// <serialization binary="true" contract="true" />
	/// <conceptualLink target="0a06b2a9-5f58-409a-ba62-639cfd77bca7" />
	#if DC
	[DataContract]
	#endif
	#if SZ
	[Serializable]
	#endif
	public class Match
	{
		/// <summary>
		/// Gets the capture name associated with the <see cref="P:MatchKit.Match.Pattern"/>.
		/// </summary>
		public string CaptureName { get { return Pattern != null ? Pattern.CaptureName : null; } }

		/// <summary>
		/// Gets the string matched by the <see cref="P:MatchKit.Match.Pattern"/>. 
		/// Gets empty string whether <see cref="P:MatchKit.Match.Success"/> is false or whether the match is not a true 
		/// string, such as for <see cref="T:MatchKit.Patterns.BosPattern"/>.
		/// </summary>
		public string MatchedString { get { return Success ? TargetText.Substring(Location.Index, MatchLength) : string.Empty; } }

		/// <summary>
		/// Gets the target text used by the <see cref="T:MatchKit.MatchContext" />.
		/// </summary>
		/// <serialization member="true" />
		#if DC
		[DataMember]
		#endif
		public string TargetText { get; private set; }

		/// <summary>
		/// Gets the pattern instance that generated this match. This value cannot be null.
		/// </summary>
		/// <serialization member="true" />
		#if DC
		[DataMember]
		#endif
		public IPattern Pattern { get; private set; }

		/// <summary>
		/// Gets the result of the match.
		/// </summary>
		/// <serialization member="true" />
		#if DC
		[DataMember]
		#endif
		public bool Success { get; private set; }

		/// <summary>
		/// Gets or sets the location of the match. This value can be an empty location whether the match is failed.
		/// </summary>
		/// <serialization member="true" />
		#if DC
		[DataMember]
		#endif
		public MatchLocation Location { get; set; }

		/// <summary>
		/// Gets or sets the length of the matched string. This value is zero whether the match is failed or 
		/// whether the match is not a true string, such as for <see cref="T:MatchKit.Patterns.BosPattern"/>.
		/// </summary>
		/// <serialization member="true" />
		#if DC
		[DataMember]
		#endif
		public int MatchLength { get; set; }

		/// <summary>
		/// Gets or sets a value that specifies whether the pattern is optional.
		/// </summary>
		/// <serialization member="true" />
		#if DC
		[DataMember]
		#endif
		public bool IsOptional { get; set; }

		/// <summary>
		/// Gets or sets a custom error message.
		/// </summary>
		/// <serialization member="true" />
		#if DC
		[DataMember]
		#endif
		public string ErrorString { get; set; }

		/// <summary>
		/// Gets or sets the children matches object. This property is used by containers patterns 
		/// such as <see cref="T:MatchKit.Patterns.SequencePattern"/>.
		/// </summary>
		/// <serialization member="true" />
		#if DC
		[DataMember]
		#endif
		public Match[] Children { get; set; }

		private object _value;
		/// <summary>
		/// Gets or sets the value associated with the match.
		/// </summary>
		/// <serialization member="true" />
		#if DC
		[DataMember]
		#endif
		public object Value { get { return IsValueMatchedString ? MatchedString : _value; } set { _value = value; } }

		/// <summary>
		/// Gets or sets a dictionary of custom values.
		/// </summary>
		/// <serialization member="true" />
		#if DC
		[DataMember]
		#endif
		public Dictionary<string, object> UserData { get; set; }

		/// <summary>
		/// Gets a value that indicates whether the <see cref="P:MatchKit.Match.Value"/> of the match is 
		/// the same of the <see cref="P:MatchKit.Match.MatchedString"/>.
		/// </summary>
		public bool IsValueMatchedString { get { return object.ReferenceEquals(_value, MatchKit.Patterns.MatchedString.Value); } }

		/// <summary>
		/// Initializes a new instance of the <see cref="T:MatchKit.Match"/> class.
		/// </summary>
		/// <param name="context">Matching context. This value cannot be null.</param>
		/// <param name="pattern">Originating pattern. This value cannot be null.</param>
		/// <param name="success">Result of the match.</param>
		public Match(MatchContext context, IPattern pattern, bool success)
		{
			if (context == null)
				throw new ArgumentNullException("context", "context cannot be null");
			if (pattern == null)
				throw new ArgumentNullException("pattern", "pattern cannot be null");

			TargetText = context.TargetText;
			Pattern = pattern;
			Success = success;
		}

		/// <summary>
		/// Finds recursively a child match given its capture name.
		/// </summary>
		public Match this[string captureName]
		{
			get
			{
				if (captureName == null)
					throw new ArgumentNullException("captureName", "captureName cannot be null");
				return MatchExtensions.GetCapture(this, captureName);
			}
		}

		/// <inheritdoc />
		public override string ToString()
		{
			return MatchedString;
		}
	}
}
